home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
a_utils
/
_archvrs
/
unix
/
tcx-1_0.lha
/
tcx-1.0
/
tcx.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-03-30
|
7KB
|
271 lines
/* tcx.c, Version 1.0, 25/3/1993 by Stewart Forster */
/************************************************************************/
/* Copyright (C) 1993 Stewart Forster */
/* This program is free software; you can redistribute it and/or modify*/
/* it under the terms of the GNU General Public License as published by*/
/* the Free Software Foundation; either version 2, or (at your option) */
/* any later version. */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program; if not, write to the Free Software */
/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/************************************************************************/
#include "config.h"
extern int errno;
int main(int, char *[]);
int is_tcx(int);
int doencode(int, int);
int
main(int argc, char *argv[])
{
struct stat dostat;
char *s;
int perms;
int infd, outfd;
char tofile[MAXPATHLEN];
char header[MAXHEADERSIZE];
struct flock lck;
unsigned char c;
/* Check to make sure we have an argument */
if(argc < 2)
{
(void)fprintf(stderr, "Usage: %s filename\n", argv[0]);
exit(-1);
}
/* Try to lstat first argument. If cannot, quit */
if(lstat(argv[1], &dostat) < 0)
{
perror(argv[1]);
exit(-1);
}
/* Make sure it's a regular file. If not, quit! */
if(!(dostat.st_mode & S_IFREG)||((dostat.st_mode & S_IFMT) == S_IFLNK))
{
(void)fprintf(stderr, "Error: %s is not a regular file\n", argv[1]);
exit(-1);
}
/* Check permissions on file, must not be setuid or setgid */
/* Then check to see if it's an executable */
if(dostat.st_mode & (S_ISUID | S_ISGID))
{
(void)fprintf(stderr, "Error: Cannot compress setuid or setgid programs.\n");
exit(-1);
}
if(! (dostat.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
{
(void)fprintf(stderr, "File does have any execute bits set. Aborting.\n");
exit(-1);
}
/* Now open file we are compressing for reading. Quit if can't. */
if((infd = open(argv[1], O_RDONLY)) < 0)
{
perror(argv[1]);
exit(-1);
}
/* Check to make sure file is not already tcx'ed */
if(is_tcx(infd))
{
(void)fprintf(stderr, "%s is already in tcx format!\n", argv[1]);
exit(0);
}
if(lseek(infd, 0, SEEK_SET) < 0)
{
perror("lseek");
exit(-1);
}
/* Open generation file, and try to mimic permissions */
/* If cannot, warn user and quit */
if(strrchr(argv[1], '/') == NULL)
(void)sprintf(tofile, ".tcx.%s", argv[1]);
else
{
(void)strcpy(tofile, argv[1]);
s = strrchr(tofile, '/');
*s = '\0';
(void)strcat(tofile, "/.tcx.");
s = strrchr(argv[1], '/');
s++;
(void)strcat(tofile, s);
}
if((outfd = open(tofile, O_EXCL | O_CREAT | O_WRONLY)) < 0)
{
if(errno != EEXIST)
{
perror(tofile);
exit(-1);
}
if((outfd = open(tofile, O_WRONLY)) < 0)
{
perror(tofile);
exit(-1);
}
}
/* Attempt to lock tofile. If can't then assume someone else */
/* is in the process of packing this file, so quit. If can */
/* then tofile must be bogus (result of crash or whatever) so */
/* we can just write over it */
lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
if(fcntl(outfd, F_SETLK, &lck) < 0)
exit(-1);
if(ftruncate(outfd, 0) < 0)
{
perror("ftruncate");
exit(-1);
}
perms = (dostat.st_mode & 0777);
if(perms & S_IXUSR) perms |= S_IRUSR;
if(perms & S_IXGRP) perms |= S_IRGRP;
if(perms & S_IXOTH) perms |= S_IROTH;
perms |= S_IWUSR;
if(chmod(tofile, perms) < 0)
{
(void)fprintf(stderr, "Cannot set proper permissions on scratch file %s\n", tofile);
(void)close(infd);
(void)close(outfd);
if(unlink(tofile) < 0)
(void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
exit(-1);
}
if(chown(tofile, dostat.st_uid, dostat.st_gid) < 0)
{
(void)fprintf(stderr, "Cannot set proper ownership on scratch file\n");
(void)close(infd);
(void)close(outfd);
if(unlink(tofile) < 0)
(void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
exit(-1);
}
/* Spit out header and start encoding executable */
(void)sprintf(header, "#!%s\n", PATHUNTCX);
if(write(outfd, header, strlen(header)) < 0) { (void)perror("write"); exit(-1); }
c = 0; if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
c = 76; if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
c = 193; if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
c = 13; if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
c = 138; if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
if(doencode(infd, outfd) != 0)
{
(void)fprintf(stderr, "Compression failed\n");
if(unlink(tofile) < 0)
(void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
exit(-1);
}
(void)close(infd);
if((infd = open(argv[1], O_WRONLY)) <= 0)
{
perror(argv[1]);
if(unlink(tofile) < 0)
(void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
exit(-1);
}
lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
if(fcntl(infd, F_SETLK, &lck) < 0)
{
if(unlink(tofile) < 0)
(void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
exit(-1);
}
/* Rename() compressed version to original */
if(rename(tofile, argv[1]) < 0)
{
perror(argv[1]);
if(unlink(tofile) < 0)
(void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
exit(-1);
}
/* Close files and hence locks */
(void)close(infd);
(void)close(outfd);
/* All done! Bye, bye. */
return(0);
}
int
is_tcx(int fd)
{
int i;
unsigned char c;
for(i = 0; i < MAXHEADERSIZE; i++)
if(read(fd, &c, 1) < 1 || c == 0)
break;
if((i >= MAXHEADERSIZE) || read(fd, &c, 1) < 1 || c != 76 || read(fd, &c, 1) < 1 || c != 193
|| read(fd, &c, 1) < 1 || c != 13 || read(fd, &c, 1) < 1 || c != 138 )
return 0;
return 1;
} /* is_tcx */
int
doencode(int infd, int outfd)
{
int pid;
union wait status;
pid = fork();
if(pid < 0) return -1;
if(pid == 0)
{
if(dup2(infd, 0) < 0) exit(-1);
(void)close(infd); /* Attach infd to stdin */
if(dup2(outfd, 1) < 0) exit(-1);
(void)close(outfd); /* Attach outfd to stdout */
#ifdef PACKEROPTS
(void)execl(PATHPACKER, "packer", PACKEROPTS, (char *)0);
#else
(void)execl(PATHPACKER, "packer", (char *)0);
#endif
exit(-1);
}
else
pid = wait(&status);
return WEXITSTATUS(status);
} /* doencode */